package bancosys.tec.services.input.driver.xls;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.poi.ss.usermodel.DateUtil;

/**
 * Classe que possui metodos utilitarios utilizados para extrair dados de arquivos XLS em um formato determinado.
 * 
 * @author Rafael Volpato
 */
public final class XLSFormatUtils {

    private static final Pattern EXCEL_NUMBER_MASK_PATTERN = Pattern.compile(".*?0+(\\.(0+))?.*");

    /**
     * Construtor. Nunca deve ser chamado
     */
    private XLSFormatUtils() {
        // do nothing
    }

    /**
     * Verificar se o formatIndex ou o formatText representam a formatação de uma data.
     * 
     * @param formatIndex index da formatação da célula.
     * @param formatText formatação da célula no formato de String.
     * @param cellValue valor da célula
     * @return <code>true</code> se o formatIndex ou o formatText representarem a formatação de uma data.
     */
    public static boolean isADateFormat(int formatIndex, String formatText, double cellValue) {
        boolean result = false;

        if (DateUtil.isValidExcelDate(cellValue)) {
            if (DateUtil.isInternalDateFormat(formatIndex)) {
                result = true;
            } else if (formatText != null) {
                String formatTextU = formatText.toUpperCase();
                if (formatTextU.indexOf("D") >= 0
                        && (formatTextU.indexOf("M") >= 0 || formatTextU.indexOf("Y") >= 0 || formatTextU.indexOf("H") >= 0 || formatTextU
                                .indexOf("S") >= 0)) {
                    result = true;
                }
            }
        }
        return result;
    }

    /**
     * Transforma um double e uma formatação em uma String que representa o <code>value</code> e respeita a quantidade de casas decimais da
     * formatação, tambem executa o arredondamento do valor se necessário.
     * 
     * @param value valor da célula
     * @param formatText formatação da célula
     * @return <code>String</code> que representa o <code>value</code>
     */
    public static String formatNumberValue(Double value, String formatText) {
        if (value.isNaN()) {
            return "NaN";
        } else if (formatText.equals("@")) {
            NumberFormat nf = new DecimalFormat("#.####################################");
            return nf.format(value);
        }
        Matcher m = EXCEL_NUMBER_MASK_PATTERN.matcher(formatText.replaceAll("\\[.*?\\]", ""));
        if (m.matches()) {
            int numeroCasasDecimais = 0;
            String decimalMask = m.group(2);
            if (decimalMask != null) {
                numeroCasasDecimais = decimalMask.length();
            }
            // Adicionar 2 casas nas celulas formatadas como percentual
            if (formatText.indexOf("%") != -1) {
                numeroCasasDecimais = numeroCasasDecimais + 2;
            }
            return BigDecimal.valueOf(value).setScale(numeroCasasDecimais, BigDecimal.ROUND_HALF_UP).toPlainString();
        } else if (Math.floor(value) == value) { // número inteiro
            return BigDecimal.valueOf(value).setScale(0, BigDecimal.ROUND_DOWN).toPlainString();
        } else {
            return BigDecimal.valueOf(value).stripTrailingZeros().toPlainString();
        }
    }

    /**
     * Retorna o valor passado como parametro na forma de data (String) no formato DD/MM/AAAA.
     * 
     * @param value valor da célula formatada como data
     * @return valor representado na forma de data no format DD/MM/AAAA
     */
    public static String formatDateValue(double value) {
        Date d = DateUtil.getJavaDate(value, false);
        StringBuilder sb = new StringBuilder();
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);

        sb.append(cal.get(Calendar.DAY_OF_MONTH));
        sb.append("/");
        sb.append(cal.get(Calendar.MONTH) + 1);
        sb.append("/");
        sb.append(cal.get(Calendar.YEAR));

        return sb.toString();
    }
}
